package com.sh.data.engine.domain.common.transformer;

import com.google.common.base.Splitter;
import com.google.common.collect.Maps;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.domain.api.model.domain.rest.DataApiTaskParamDomain;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.TypeMismatchException;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: zigui.zdf
 * @description:
 * @date: 2020/11/11 15:27
 */
@Slf4j
public class DataApiParamConverter extends SimpleTypeConverter {

    public static final Object EMPTY = new Object();

    private static final Splitter SPLITTER = Splitter.on(",").trimResults().omitEmptyStrings();

    private static final String[] DTPATTERNS =
        new String[]{"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd", "yyyy/MM/dd", "yyyyMMdd"};

    private static Map<String, Class<?>> dataTypeMap =
        Maps.newHashMap(
            new HashMap<String, Class<?>>() {
                private static final long serialVersionUID = -5991258361225643746L;

                {
                    put("BOOLEAN", Boolean.class);
                    put("INT", Integer.class);
                    put("LONG", Long.class);
                    put("FLOAT", Float.class);
                    put("DOUBLE", Double.class);
                    put("STRING", String.class);
                }
            });

    public Map<DataApiTaskParamDomain, Object> convertParams(
        List<DataApiTaskParamDomain> configParams, Map<String, String> actualParams) {

        Map<DataApiTaskParamDomain, Object> result = new HashMap<>();

        String errActualParamValue = null, errParamDataType = null;

        try {
            for (DataApiTaskParamDomain configParam : configParams) {
                String paramName = configParam.getParamName();
                Integer paramOperator = configParam.getParamOperator();
                String paramDataType = configParam.getParamDataType();
                String actualParamValue = actualParams.get(paramName);
                Class<?> actualParamType = dataTypeMap.get(paramDataType.toUpperCase());

                Object paramValueToUse = EMPTY;

                if (Objects.isNull(actualParamValue)
                    || (Objects.nonNull(configParam.getParamRequire())
                    && configParam.getParamRequire() == 0
                    && "".equals(actualParamValue))) {
                    result.put(configParam, paramValueToUse);
                    continue;
                }

                errActualParamValue = actualParamValue;
                errParamDataType = paramDataType;

                if (paramOperator == null) {
                    paramValueToUse = convertIfNecessary(actualParamValue, actualParamType);
                    // 指定'like'操作时无论指定的数据类型是什么都需要保留为原始的String类型
                } else if (paramOperator == 1 || paramOperator == 9) {
                    paramValueToUse = actualParamValue;
                    // 指定'in'或'between'操作时需要将原始字符串转换为集合类型
                } else if (paramOperator == 2 || paramOperator == 3 || paramOperator == 10) {
                    List<String> actualParamVals = SPLITTER.splitToList(actualParamValue);
                    paramValueToUse =
                        actualParamVals.stream()
                            .map(ele -> convertIfNecessary(ele, actualParamType))
                            .collect(Collectors.toList());
                } else {
                    // 日期类型需要特殊处理
                    if (StringUtils.containsIgnoreCase(paramDataType, "date")) {
                        paramValueToUse = DateUtils.parseDate(actualParamValue, DTPATTERNS);
                    } else if (StringUtils.containsIgnoreCase(paramDataType, "timestamp")) {
                        Date date = DateUtils.parseDate(actualParamValue, DTPATTERNS);
                        Timestamp dateTime = new Timestamp(date.getTime());
                        paramValueToUse = dateTime;
                    } else {
                        paramValueToUse = convertIfNecessary(actualParamValue, actualParamType);
                    }
                }

                // 如果值是boolean类型，true为1，false为0，参考dataworks
                if (paramValueToUse instanceof Boolean) {
                    paramValueToUse = (Boolean) paramValueToUse ? 1 : 0;
                }

                result.put(configParam, paramValueToUse);
            }
        } catch (TypeMismatchException e) {
            throw new BusinessException(
                String.format(
                    "param value [%s] convert to [%s] type error",
                    e.getValue(), e.getRequiredType().getSimpleName()));
        } catch (Exception e) {
            throw new BusinessException(
                String.format(
                    "param value [%s] convert to [%s] type error",
                    errActualParamValue, errParamDataType));
        }
        return result;
    }
}
